// OTIMIZADO
/**
* Vidget - Widget de vídeo interativo
* Versão 2.0
*/
console.log('%cVidget%cV2.0', 'padding:1px 3px; color: lightgreen; background-color: black', 'padding:1px 3px 1px 0px; color: orange; background-color: black');
// Configurações globais
const VIDGET_CONFIG = {
STORAGE_URL: 'https://phxkpzehxsbteunlmdoq.supabase.co/storage/v1/object/public/vidget::videos',
SUPABASE_URL: 'https://phxkpzehxsbteunlmdoq.supabase.co',
SUPABASE_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBoeGtwemVoeHNidGV1bmxtZG9xIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDMxNjg2MDcsImV4cCI6MjAxODc0NDYwN30.oEfBNB49pgdWuGIDYoZf78J9nzZyzrfwZ6cX_OPOF3A',
UPDATE_INTERVAL: 5, // Intervalo para atualização de métricas (segundos)
SWIPE_THRESHOLD: 50, // Limite para detecção de swipe
MOBILE_BREAKPOINT: 768, // Breakpoint para dispositivos móveis
METRICS_BUCKETS: {
LOW: "0-25",
MID_LOW: "26-50",
MID_HIGH: "51-75",
HIGH: "76-100"
},
HIDE_TIMEOUT: 20000, // 20 segundos para reexibir o widget
ICONS: {
CLOSE: 'https://app.vidget.com.br/assets/public/i-close-icon-2.svg',
CLOSE_MOBILE: 'https://app.vidget.com.br/assets/public/i-close-icon-mob.svg',
SOUND: 'https://app.vidget.com.br/assets/public/i-sound.svg',
SOUND_MOBILE: 'https://app.vidget.com.br/assets/public/i-sound-mob.svg',
MUTE: 'https://app.vidget.com.br/assets/public/i-mute.svg',
MUTE_MOBILE: 'https://app.vidget.com.br/assets/public/i-mute-mob.svg',
PREV: 'https://app.vidget.com.br/assets/public/i-prev-arrow-2.svg',
NEXT: 'https://app.vidget.com.br/assets/public/i-next-arrow-2.svg',
SHARE: 'https://app.vidget.com.br/assets/public/i-whats-white.svg',
COPY_LINK: 'https://app.vidget.com.br/assets/public/i-share-white.svg',
COPY: 'https://app.vidget.com.br/assets/public/i-copy-blue.svg',
WHATSAPP: 'https://app.vidget.com.br/assets/public/i-whatsapp.svg'
},
ASSETS_BASE: 'https://app.vidget.com.br/assets/public/'
};
// Estado global
let globalSupabaseInstance = null;
let videoSet = [];
let currentVideoIndex = 0;
let currentVideoElement = null;
let lastTimeUpdate = 0;
let isChangingVideo = false;
let arrowsClicked = false;
let isExpanded = true;
let isDragging = false;
let isProcessingSwipe = false;
let toggleLock = false;
let touchStartY = 0;
let lastTouchY = 0;
let startTime = null;
let dragStartTime = null;
let vidgetContainer;
/**
* Funções de utilidade (Utility Functions)
*/
const VidgetUtils = {
/**
* Adiciona estilo CSS dinamicamente
* @param {string} cssString String CSS a ser adicionada
*/
injectCSS: function (cssString) {
const style = document.createElement('style');
style.textContent = cssString;
document.head.appendChild(style);
console.log('CSS injetado:', cssString.substring(0, 50) + '...');
},
/**
* Adiciona Google Fonts dinamicamente
*/
addGoogleFonts: function () {
const fontLink = document.createElement('link');
fontLink.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap';
fontLink.rel = 'stylesheet';
document.head.appendChild(fontLink);
},
/**
* Normaliza URL removendo www e padronizando formatação
* @param {string} url URL para normalizar
* @returns {string} URL normalizada
*/
normalizeUrlRemoveWWW: function (url) {
if (!url) return '';
// Se não tiver protocolo, adiciona https
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'https://' + url;
}
try {
let urlObj = new URL(url);
// Remove 'www.'
let hostname = urlObj.hostname.replace(/^www\./, '');
let normalizedUrl = urlObj.protocol + '//' + hostname + urlObj.pathname;
// Remove barra final e deixa tudo minúsculo
normalizedUrl = normalizedUrl.replace(/\/$/, '').toLowerCase();
// Reinsere query se for /busca ou tiver variant_id
if (urlObj.pathname === '/busca') {
normalizedUrl += urlObj.search;
} else if (urlObj.searchParams.has('variant_id')) {
let variantId = urlObj.searchParams.get('variant_id');
normalizedUrl += '?variant_id=' + variantId;
}
return normalizedUrl;
} catch (error) {
console.error('Erro ao normalizar URL (removeWWW):', error);
return url.toLowerCase();
}
},
/**
* Normaliza URL mantendo www e padronizando formatação
* @param {string} url URL para normalizar
* @returns {string} URL normalizada
*/
normalizeUrlKeepWWW: function (url) {
if (!url) return '';
// Se não tiver protocolo, adiciona https
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'https://' + url;
}
try {
let urlObj = new URL(url);
// Mantém o www no hostname
let normalizedUrl = urlObj.origin + urlObj.pathname;
normalizedUrl = normalizedUrl.replace(/\/$/, '').toLowerCase();
if (urlObj.pathname === '/busca') {
normalizedUrl += urlObj.search;
} else if (urlObj.searchParams.has('variant_id')) {
let variantId = urlObj.searchParams.get('variant_id');
normalizedUrl += '?variant_id=' + variantId;
}
return normalizedUrl;
} catch (error) {
console.error('Erro ao normalizar URL (keepWWW):', error);
return url.toLowerCase();
}
},
/**
* Converte texto em HTML com links clicáveis
* @param {string} text Texto para converter
* @returns {string} HTML com links
*/
convertTextToLinks: function (text) {
if (!text) return '';
const urlRegex = /(\bhttps?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]|(?:\b[a-z][a-z0-9-]*\.)+[a-z]{2,}\/[-A-Z0-9+&@#\/%=~_|!:,.;]*\/?)/ig;
return text.replace(urlRegex, function (url) {
if (!/^https?:\/\//i.test(url)) {
return `${url}`;
}
const displayUrl = url.replace(/^https?:\/\//, '');
return `${displayUrl}`;
});
},
/**
* Verifica se o elemento possui box-shadow
* @param {HTMLElement} element Elemento para verificar
* @returns {boolean} Se possui box-shadow
*/
hasBoxShadow: function (element) {
const style = window.getComputedStyle(element);
return style.boxShadow !== 'none' && style.boxShadow !== '';
},
/**
* Obtém o bucket de conclusão com base na porcentagem
* @param {number} completionPercentage Porcentagem de conclusão
* @returns {string} Bucket de conclusão
*/
getCompletionBucket: function (completionPercentage) {
if (completionPercentage <= 25) return VIDGET_CONFIG.METRICS_BUCKETS.LOW;
if (completionPercentage <= 50) return VIDGET_CONFIG.METRICS_BUCKETS.MID_LOW;
if (completionPercentage <= 75) return VIDGET_CONFIG.METRICS_BUCKETS.MID_HIGH;
return VIDGET_CONFIG.METRICS_BUCKETS.HIGH;
},
/**
* Pré-carrega vídeos adjacentes para melhorar a experiência
* @param {number} index Índice do vídeo atual
*/
preloadAdjacentVideos: function (index) {
if (!videoSet || videoSet.length <= 1) return;
// Pré-carrega todos os vídeos, não apenas adjacentes
for (let i = 0; i < videoSet.length; i++) {
if (i !== index) { // Não recarregue o atual
const video = document.createElement('video');
video.src = `${VIDGET_CONFIG.STORAGE_URL}/${videoSet[i].url}`;
video.preload = 'auto';
video.style.display = 'none';
document.body.appendChild(video);
// Força o carregamento
video.load();
// Remove depois de pré-carregar
setTimeout(() => {
if (document.body.contains(video)) {
document.body.removeChild(video);
}
}, 5000);
}
}
}
};
/**
* Estilos CSS para o Vidget
*/
const VidgetStyles = {
baseCSS: `
#vidget__container {
width: 24vw;
height: calc(22vw* 1.7692);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#000000",endColorstr="#000000",GradientType=1);
position: fixed;
z-index: 999999999;
font-family: 'Inter', sans-serif;
font-size: 16px;
bottom: 20px;
overflow: hidden;
background: rgba(0, 0, 0, 0.35);
transition: opacity 0.3s ease-in-out;
visibility: hidden; /* Inicialmente oculto */
}
#vidget__container.loaded.shadow-applied.minimized {
border-radius: 50% !important;
}
#vidget__container.shadow-applied.loaded:not(.minimized) {
border-radius: 1rem !important;
}
#vidget__container.loaded {
opacity: 1;
pointer-events: auto;
visibility: visible;
}
#vidget__container.loading {
opacity: 0;
pointer-events: none;
visibility: hidden;
}
#vidget__container.minimized.shadow-applied.minimized.size-p {
width: 6vw !important;
height: 6vw !important;
}
#vidget__container.minimized.shadow-applied.minimized.size-m {
width: 8vw !important;
height: 8vw !important;
}
#vidget__container.minimized.shadow-applied.minimized.size-g {
width: 12vw !important;
height: 12vw !important;
}
@media screen and (max-width: 768px) {
#vidget__container.minimized.shadow-applied.minimized.size-p, #vidget__container.minimized.shadow-applied.minimized.size-m, #vidget__container.minimized.shadow-applied.minimized.size-g {
width: 20vw !important;
height: 20vw !important;
}
#vidget__container.minimized.size-g video, #vidget__container.minimized.size-m video, #vidget__container.minimized.size-p video {
width: 20vw !important;
height: 20vw !important;
}
}
#vidget__container.minimized.size-g video {
width: 12vw ;
height: 12vw ;
}
#vidget__container.minimized .vidget__progress-container {
display: none;
}
#vidget__container.minimized #share-button {
display: none !important;
}
.article-content {
display: flex;
gap: .65rem;
}
.btn-close {
padding: 0;
z-index: 999;
}
.full-mode-article p:first-of-type {
margin-top: 10px !important;
}
.full-mode-article p {
margin-bottom: 20px !important;
}
#vidget__container article p {
font-family: 'Inter', sans-serif !important;
}
#vidget__container.no-border article {
margin-left: 3px !important;
}
@media screen and (max-width: 768px) {
#vidget__container {
width: 100% !important;
height: 100% !important;
margin-left: 0px;
border-radius: 0 !important;
z-index: 99999999999;
bottom: 0px;
}
#vidget__container:not(.minimized) {
bottom: 0px !important;
}
#vidget__container.minimized.shadow-applied.minimized {
width: 18vw !important;
height: 18vw !important;
}
#vidget__container.minimized {
bottom: 20px;
}
#vidget__container.minimized video {
top: 0px !important;
}
#vidget__container article div a[data-vidget-url] {
width: calc(100% - 10vw - 235px) !important;
font-size: .8em !important;
bottom: 4px !important;
padding: 3px 3px !important;
}
#vidget__container article {
width: 100% !important;
height: fit-content !important;
bottom: 0 !important;
margin: 10px 0px 4px 0px !important;
}
@media screen and (max-width: 768px) {
#vidget__container article{
width: 95% !important;
height: fit-content !important;
bottom: 0 !important;
margin: 10px 0px 10px 10px !important;
}
}
#vidget__container article p {
line-height: 16px !important;
font-size: .9em !important;
font-family: 'Inter', sans-serif !important;
padding-top: .5rem !important;
}
.article-content {
gap: 1rem;
}
#vidget__container.minimized .vidget__video-container {
width: 19vw !important;
height: 19vw !important;
border-radius: 50% !important;
}
#vidget__container.minimized .vidget__video-container.no-box-shadow {
width: 18vw;
height: 18vw;
}
#vidget__container.minimized video, #vidget__container.minimized div[data-vidget-video-overlay] {
width: 20vw !important;
height: 20vw !important;
}
#vidget__container.minimized video {
border-radius: 50% !important;
}
#vidget__container.minimized {
width: 20vw !important;
height: 20vw !important;
box-shadow: none;
}
}
`,
progressBarCSS: `
.vidget__progress-container {
position: absolute;
top: 6px;
left: 0;
z-index: 99999;
width: 90%;
height: 6px;
display: flex;
margin-left: 15px;
gap: 4px; /* Espaço entre as barras */
}
.vidget__progress-bar {
height: 6px;
flex: 1; /* Distribui o espaço igualmente */
background-color: rgba(255, 255, 255, 0.3); /* Cor inativa */
border-radius: 2rem;
overflow: hidden; /* Para conter a barra de progresso */
position: relative;
}
.vidget__progress-bar.active {
background-color: rgba(255, 255, 255, 0.9);
}
.vidget__progress-bar.completed {
background-color: rgba(255, 255, 255, 0.9);
}
`,
controlsCSS: `
#vidget__container article {
width: 95%;
height: fit-content;
bottom: 0;
margin: 10px auto;
border-radius: 5px;
display: flex;
}
#vidget__container.no-border article {
width: 100%;
}
.vidget__video-container {
transition: transform 0.5s ease-in-out;
height: 100%;
width: 100%;
}
#vidget__container.minimized .vidget__video-container {
height: auto;
}
.video-fade-out {
opacity: 0;
transition: opacity 0.5s ease-out;
}
.video-fade-in {
opacity: 1;
transition: opacity 0.5s ease-in;
}
#vidget__container.minimized video {
width: 9vw;
height: 9vw;
}
#vidget__container.minimized div[data-vidget-video-overlay] {
width: 8.5vw;
height: 8.5vw;
}
#vidget__container.minimized article,
#vidget__container.minimized button {
display: none !important;
}
div[data-vidget-video-overlay] {
width: 100%;
height: 102%;
}
#vidget__container video {
width: 100%;
border-radius: 0.75rem;
object-fit: cover;
height: 100%;
width: 100%;
top: 0;
}
@media screen and (max-width: 768px) {
#vidget__container video {
border-radius: 0;
}
}
#vidget__container video.with-border {
max-width: 100%;
width: 100%;
height: 95vh;
max-height: 100%;
border-radius: 0.75rem;
object-fit: cover;
top: 0px;
}
#vidget__container article {
position: absolute;
background: rgba(21, 21, 21, 0.62);
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
z-index: 99999999;
}
#vidget__video-overlay > article > div > div > div > p.mb-2 {
font-weight: 700 !important;
font-size: 1.25em;
text-wrap: nowrap;
max-width: 100%;
text-overflow: ellipsis;
overflow: hidden;
}
#vidget__container button {
position: absolute;
}
.btn-close {
cursor: pointer;
}
.btn-close img {
position: relative;
width: 100%;
}
.btn-close.vidget-btn-close {
background:
url('${VIDGET_CONFIG.ICONS.CLOSE}') no-repeat center, /* imagem */
#15151575 !important; /* cor de fundo com transparência */
backdrop-filter: blur(5px);
border-radius: 50%;
padding: .75rem;
top: 20px !important;
}
#vidget__container article img {
width: 35% !important;
max-width: 100px;
border-radius: 8px;
height: 100px;
object-fit: cover;
}
#vidget__container article div {
padding: 10px 12px;
line-height: 18px;
color: #fff;
}
#vidget__container article div > * {
margin: 0;
padding: 0;
width: 100%;
font-family: 'Inter', sans-serif;
text-wrap: nowrap;
max-width: 100%;
text-overflow: ellipsis;
overflow: hidden;
}
#vidget__container article div p[data-vidget-price] {
font-size: 0.8em;
font-family: 'Inter', sans-serif;
}
#vidget__container article div a[data-vidget-url] {
position: absolute;
bottom: 8px;
width: calc(100% - 10vw + -100px);
color: #fff;
padding: 6px 8px;
border-radius: 3px;
font-size: 0.75em;
font-weight: 700;
text-align: center;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 1px;
right: 8px
}
#vidget__container article div a[data-vidget-url]:hover {
opacity: 1;
}
#vidget__container button {
top: 10px;
right: -5px;
border: none;
width: 40px;
height: 40px;
}
.navigation-arrows {
position: absolute;
top: 50%;
width: calc(100% - 10px);
z-index: 999999;
display: flex;
flex-direction: column;
}
.prev-arrow, .next-arrow {
background-color: transparent;
border: none;
font-size: 24px;
color: white;
cursor: pointer;
padding: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.prev-arrow {
top: 30px !important;
transform: rotate(-0deg);
}
.next-arrow {
top: -40px !important;
transform: rotate(-0deg);
}
.navigation-arrows img {
pointer-events: none;
}
.prev-arrow {
background:
url('${VIDGET_CONFIG.ICONS.PREV}') no-repeat center / contain, /* ajusta o ícone */
#15151575; /* cor de fundo com transparência */
backdrop-filter: blur(5px);
border-radius: 50%;
top: 10px !important;
background-size: 50%;
}
.next-arrow {
background:
url('${VIDGET_CONFIG.ICONS.NEXT}') no-repeat center / contain, /* ajusta o ícone */
#15151575; /* cor de fundo com transparência */
backdrop-filter: blur(5px);
border-radius: 50%;
background-size: 50%;
}
#sound-on {
background: url('${VIDGET_CONFIG.ICONS.SOUND}') no-repeat center, #15151575;
backdrop-filter: blur(5px);
right: 5px !important;
border-radius: 50%;
padding: 1rem;
top: 67.5% !important;
cursor: pointer;
background-size: 100%;
z-index: 999999;
}
#copy-link-button {
background: url(${VIDGET_CONFIG.ICONS.COPY_LINK}) no-repeat center, #15151575;
right: 6px !important;
border-radius: 50%;
padding: .75rem;
top: 110px !important;
cursor: pointer;
z-index: 999999;
}
#share-button {
background: url(${VIDGET_CONFIG.ICONS.SHARE}) no-repeat center, #15151575;
right: 6px !important;
border-radius: 50%;
padding: .75rem;
top: 160px !important;
cursor: pointer;
z-index: 999999;
}
#sound-off {
background: url('${VIDGET_CONFIG.ICONS.MUTE}') no-repeat center, #15151575;
backdrop-filter: blur(5px);
right: 5px !important;
border-radius: 50%;
padding: 1rem;
top: 67.5% !important;
cursor: pointer;
background-size: 110%;
z-index: 999999;
}
#video-slider {
overflow: hidden;
position: relative;
height: 100%;
}
.video-item {
position: absolute;
width: 100%;
height: 100%;
transition: transform 0.5s ease-in-out;
}
.video-item {
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-perspective: 1000;
perspective: 1000;
}
.btn-close {
right: 5px !important;
background: transparent;
}
@media screen and (max-width: 768px) {
.prev-arrow, .next-arrow {
font-size: 20px;
}
.prev-arrow, .next-arrow {
padding: 1.25rem
}
.next-arrow {
top: -75px !important;
}
#sound-on {
background: url('${VIDGET_CONFIG.ICONS.SOUND_MOBILE}') no-repeat center;
top: 75% !important;
padding: 1.5rem;
right: 5px !important;
background-size: 100% !important;
}
#sound-off {
background: url('${VIDGET_CONFIG.ICONS.MUTE_MOBILE}') no-repeat center;
padding: 1.5rem;
right: 5px !important;
top: 75% !important;
background-size: 100% !important;
}
.btn-close.vidget-btn-close {
background: url('${VIDGET_CONFIG.ICONS.CLOSE_MOBILE}') no-repeat center !important;
padding: 1.5rem;
border-radius: 50%;
background-size: 100% !important;
}
#vidget__container video {
height: 100vh;
}
#vidget__container video.with-border {
height: 100vh;
}
#vidget__container article img {
width: 35% !important;
max-width: 100%;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
object-fit: cover;
}
#vidget__container article div {
padding: 10px;
line-height: 18px;
color: #fff;
}
#vidget__container article div > * {
margin: 0;
padding: 0;
width: 100%;
}
}
`,
playButtonCSS: `
#vidget-play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
background: rgba(0, 0, 0, 0.5);
border: none;
border-radius: 50%;
cursor: pointer;
z-index: 999999;
display: none;
backdrop-filter: blur(5px);
transition: all 0.3s ease;
margin-top: 75%
}
#vidget-play-button:hover {
background: rgba(0, 0, 0, 0.7);
transform: translate(-50%, -50%) scale(1.1);
}
#vidget-play-button::before {
content: '';
position: absolute;
top: 50%;
left: 55%;
transform: translate(-50%, -50%);
width: 0;
height: 0;
border-style: solid;
border-width: 12px 0 12px 20px;
border-color: transparent transparent transparent #ffffff;
}
#vidget__container.minimized #vidget-play-button {
width: 40px;
height: 40px;
display: none !important;
}
#vidget__container.minimized #vidget-play-button::before {
border-width: 8px 0 8px 14px;
}
@media screen and (max-width: 768px) {
#vidget-play-button {
margin-top: 100%
}
}
`,
additionalCSS: `
.vidget__video-container {
position: relative;
overflow: hidden;
}
.vidget__video-container video {
position: absolute;
width: 100%;
height: 100%;
transition: top 1.6s ease-out;
}
`,
/**
* Inicializa todos os estilos CSS
*/
initStyles: function () {
VidgetUtils.addGoogleFonts();
VidgetUtils.injectCSS(this.baseCSS);
VidgetUtils.injectCSS(this.progressBarCSS);
VidgetUtils.injectCSS(this.controlsCSS);
VidgetUtils.injectCSS(this.playButtonCSS);
VidgetUtils.injectCSS(this.additionalCSS);
console.log('Todos os estilos inicializados');
}
};
// Inicialização e configuração do Vidget
function initVidget() {
// Injetar estilos CSS
VidgetStyles.initStyles();
// Obter o parâmetro de localização da URL do script
const vidget__script_url = new URL(document.currentScript.src);
const vidget__location_param = decodeURIComponent(vidget__script_url.searchParams.get('location'));
// Criar o contêiner principal
initContainer();
// Iniciar o Vidget
initSupabase((supabaseInstance) => {
getVideosByUrl(supabaseInstance, vidget__location_param)
.then(response => {
if (response && response.length > 0) {
videoSet = response;
vidgetContainer.innerHTML = '';
initializeVideoOverlay(supabaseInstance, response);
VidgetUtils.preloadAdjacentVideos(0);
} else {
vidgetContainer.style.display = 'none';
}
})
.catch(error => {
console.error('Erro durante a inicialização de vídeos:', error);
});
});
// Listeners para salvar métricas quando a página for fechada
window.addEventListener('beforeunload', async (event) => {
if (currentVideoElement) {
await saveMetricsOnInterruption(
globalSupabaseInstance,
videoSet[currentVideoIndex].id,
lastTimeUpdate
);
}
});
document.addEventListener('visibilitychange', async () => {
if (document.hidden && currentVideoElement) {
await saveMetricsOnInterruption(
globalSupabaseInstance,
videoSet[currentVideoIndex].id,
lastTimeUpdate
);
}
});
}
// Inicializa o container do Vidget
function initContainer() {
// Create the container principal do Vidget
vidgetContainer = document.createElement('div');
vidgetContainer.id = 'vidget__container';
// MELHORIA: Use opacity em vez de visibility
vidgetContainer.style.opacity = '0';
vidgetContainer.style.transition = 'opacity 0.3s ease-in-out';
vidgetContainer.classList.add('minimized');
document.body.appendChild(vidgetContainer);
// Create overlay for fullscreen mode
const fullScreenOverlay = document.createElement('div');
fullScreenOverlay.id = 'fullScreenOverlay';
fullScreenOverlay.style.position = 'fixed';
fullScreenOverlay.style.top = '0';
fullScreenOverlay.style.left = '0';
fullScreenOverlay.style.width = '100vw';
fullScreenOverlay.style.height = '100vh';
fullScreenOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
fullScreenOverlay.style.display = 'none';
fullScreenOverlay.style.zIndex = '999';
document.body.appendChild(fullScreenOverlay);
}
// Inicializa a conexão com Supabase
function initSupabase(callback) {
// Adiciona o script do Supabase
const supabaseScript = document.createElement('script');
supabaseScript.type = 'text/javascript';
supabaseScript.src = 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js';
document.body.appendChild(supabaseScript);
// Quando o script for carregado, cria a instância do Supabase
supabaseScript.onload = function () {
if (typeof supabase === 'undefined') {
console.error('Supabase não está definido.');
return;
}
globalSupabaseInstance = supabase.createClient(
VIDGET_CONFIG.SUPABASE_URL,
VIDGET_CONFIG.SUPABASE_KEY
);
if (typeof callback === 'function') {
callback(globalSupabaseInstance);
}
};
}
// Busca vídeos no Supabase com base na URL
async function getVideosByUrl(supabaseInstance, targetUrl) {
if (!targetUrl) return null;
// 1. Normaliza removendo 'www.'
let normalizedUrlNoWWW = VidgetUtils.normalizeUrlRemoveWWW(targetUrl);
let videos = await fetchVideosByURL(supabaseInstance, normalizedUrlNoWWW);
// 2. Se não encontrar nada, tenta normalização que mantém 'www.'
if (!videos || videos.length === 0) {
console.log("Nada com URL sem www. Tentando com www...");
let normalizedUrlWithWWW = VidgetUtils.normalizeUrlKeepWWW(targetUrl);
videos = await fetchVideosByURL(supabaseInstance, normalizedUrlWithWWW);
}
// 3. Se ainda assim não encontrou nada, tenta fallback com base original
if (!videos || videos.length === 0) {
console.log("Ainda não achou. Tentando URL base...");
const urlObject = new URL(targetUrl);
let baseUrl = urlObject.origin + urlObject.pathname;
videos = await fetchVideosByURL(supabaseInstance, baseUrl);
}
// 4. Se no final não encontrar nada, retorna null
if (!videos || videos.length === 0) {
console.log("Nenhum vídeo encontrado para a URL especificada.");
return null;
}
// Continua com o resto (pegar video_set_id, filtrar "active", etc.)
let videoSetIds = videos.map(video => video.video_set_id);
let uniqueVideoSetIds = [...new Set(videoSetIds)];
let { data: videoSets, error: errorVideoSets } = await supabaseInstance
.from('vidget::video_sets')
.select(`id, image_url, status`)
.in('id', uniqueVideoSetIds);
if (errorVideoSets) {
console.error('Erro ao buscar conjuntos de vídeos:', errorVideoSets);
return null;
}
let activeVideoSets = videoSets.filter(set => set.status === 'active');
let videosWithImageUrls = videos.map(video => {
let videoSet = activeVideoSets.find(set => set.id === video.video_set_id);
return {
...video,
image_url_from_set: videoSet ? videoSet.image_url : null
};
});
return videosWithImageUrls;
}
// Busca vídeos com base na URL fornecida
async function fetchVideosByURL(supabaseInstance, url) {
try {
// Primeira tentativa: buscar em urlVideoSets (array)
let { data: videosFromArray, error: errorFromArray } = await supabaseInstance
.from('vidget::videos')
.select('title, url, metadata, id, video_set_id')
.filter('metadata->urlVideoSets', 'cs', `[{"value": "${url}"}]`);
// Se não encontrou em urlVideoSets, tenta urlVideoSet (string)
if (!videosFromArray || videosFromArray.length === 0) {
console.log('Não encontrou em urlVideoSets, tentando urlVideoSet');
let { data: videosFromSingle, error: errorFromSingle } = await supabaseInstance
.from('vidget::videos')
.select('title, url, metadata, id, video_set_id')
.eq('metadata->>urlVideoSet', url);
if (errorFromSingle) {
console.error('Erro ao buscar vídeos de urlVideoSet:', errorFromSingle);
return null;
}
return videosFromSingle;
}
return videosFromArray;
} catch (error) {
console.error('Erro em fetchVideosByURL:', error);
return null;
}
}
// Busca um vídeo específico pelo ID
async function getVideoById(supabaseInstance, videoId) {
let query = supabaseInstance
.from('vidget::videos')
.select('title, url, metadata, id')
.eq('id', videoId)
.single();
const { data, error } = await query;
if (error) {
console.error('Erro ao buscar vídeo:', error);
return null;
}
return data;
}
// Cria o markup HTML para o overlay do vídeo
function createVideoMarkup(productUrl, metadata = {}, image_url_from_set = null) {
console.log("URL da imagem do conjunto de vídeos:", image_url_from_set);
// Compatibilidade: verificar estrutura dos metadados
const isNewFormat = 'showTitle' in metadata || 'showDescription' in metadata || 'showPrice' in metadata || 'buttonText' in metadata;
// Extrair dados de acordo com o formato
const {
description,
productPrice,
price,
title,
productCardPrice,
image_url,
type,
buttonUrl,
buttonText,
showTitle,
showDescription,
showPrice,
showButton,
buttonColor
} = metadata;
// Gerar título baseado no formato dos metadados
const displayTitle = isNewFormat ? (showTitle ? title : '') : title;
// Gerar descrição baseada no formato dos metadados
const displayDescription = isNewFormat
? (showDescription ? description : '')
: description;
// Gerar preço baseado no formato dos metadados
const displayPrice = isNewFormat
? (showPrice ? (price || productPrice || productCardPrice) : '')
: (productPrice || productCardPrice);
// URL do botão baseada no formato dos metadados
const displayButtonUrl = isNewFormat
? (showButton ? (buttonUrl || productUrl) : '')
: productUrl;
// Texto do botão baseado no formato dos metadados
const displayButtonText = isNewFormat
? (showButton ? (buttonText || 'Ver produto') : '')
: 'Ver produto';
// Cor do botão (apenas no novo formato)
const buttonStyle = isNewFormat && buttonColor
? `background-color: #${buttonColor}; border-color: #${buttonColor}; color: white;`
: '';
// Usar 'image_url_from_set' se disponível; caso contrário, usar 'image_url' ou uma imagem padrão
const imageUrl = image_url_from_set || image_url;
// Verificar se deve mostrar a imagem (compatibilidade)
const shouldShowImage = isNewFormat
? metadata.showThumbnail
: (imageUrl && type === 'productCard');
// Construir elemento de imagem
const imageDiv = shouldShowImage && imageUrl
? ``
: `
`;
// Aplica padding ao parágrafo de descrição apenas quando o tipo é 'description'
const descriptionStyle = (!isNewFormat && type === 'description') ? 'padding: 0px 12px;' : '';
// Preparar HTML dos detalhes do produto
let productDetailsHTML = '';
if (isNewFormat || (!isNewFormat && type !== 'empty-field')) {
productDetailsHTML = `